package cmd

import (
	"context"
	"fmt"
	log "gitee.com/xuyiping_admin/pkg/logger/logrus"
	"gitee.com/xuyiping_admin/pkg/svcutil"
	"gitee.com/xuyiping_admin/pkg/xerr"
	"os"
	"time"

	"github.com/spf13/cobra"
)

type CommandHandle func(ctx context.Context, args []string) error

type CommandOption func(command *cobra.Command)

func Addr() string {
	if v := os.Getenv("CMD_HTTP_ADDR"); v != "" {
		return v
	}
	return ":8000"
}

func Add(mainCmd *cobra.Command, use string, handle func(cmd *cobra.Command, args []string), short string) {
	command := &cobra.Command{
		Use:   use,
		Short: short,
		Run:   handle,
	}
	command.AddCommand(command)
}

// WaitFor 绑定子命令，并且提供持续运行能力(内部函数结束就会终止，一般用于不断更新 异步任务系统 - K8S Deployment)
func WaitFor(mainCmd *cobra.Command, use string, f func(stop <-chan struct{}) error, short string, options ...CommandOption) {
	command := &cobra.Command{
		Use:   use,
		Short: short,
		Run: func(cmd *cobra.Command, args []string) {
			log.Infof("[%s] task start", use)
			defer func() {
				log.Infof("[%s] task finished", use)
			}()

			// 持续运行，直到内部逻辑退出
			svcutil.WaitFor(Addr(), f)
		},
	}

	for _, opt := range options {
		opt(command)
	}

	mainCmd.AddCommand(command)
}

// Bind 绑定子命令，并且提供持续运行能力(结束了仍然持续运行，一般用于不断更新 K8S Job)
func Bind(mainCmd *cobra.Command, use string, handle CommandHandle, short string, options ...CommandOption) {
	command := &cobra.Command{
		Use:   use,
		Short: short,
		Run: func(cmd *cobra.Command, args []string) {
			ctx := context.Background()

			log.Infof("[%s] task start", use)
			defer func() {
				log.Infof("[%s] task finished", use)
			}()

			svcutil.NeverStop(Addr(), func() {
				startTime := time.Now()
				var notification string
				if err := handle(ctx, args); err != nil {
					_ = xerr.ReportError(ctx, err)
					notification = fmt.Sprintf(cmdErrTemplate, use, args, time.Now().Sub(startTime), err)
				} else {
					notification = fmt.Sprintf(cmdFinishedTemplate, use, args, time.Now().Sub(startTime))
				}

				log.Info(notification)
			})
		},
	}

	for _, opt := range options {
		opt(command)
	}

	mainCmd.AddCommand(command)

}

// Instant 绑定子命令，只能运行一次就停止
func Instant(mainCmd *cobra.Command, use string, handle CommandHandle, short string, options ...CommandOption) {
	ctx := context.Background()
	command := &cobra.Command{
		Use:   use,
		Short: short,
		Run: func(cmd *cobra.Command, args []string) {
			startTime := time.Now()
			var notification string

			log.Infof("[%s] task start", use)
			defer func() {
				log.Infof("[%s] task finished", use)
			}()

			if err := handle(ctx, args); err != nil {
				notification = fmt.Sprintf(cmdErrTemplate, use, args, time.Now().Sub(startTime), err)
				_ = xerr.ReportError(ctx, err)
			} else {
				notification = fmt.Sprintf(cmdFinishedTemplate, use, args, time.Now().Sub(startTime))
			}

			log.Info(notification)
		},
	}

	for _, opt := range options {
		opt(command)
	}

	mainCmd.AddCommand(command)
}

var cmdFinishedTemplate = `## 脚本执行完成
%s done
args %v
执行时间: %s`

var cmdErrTemplate = `
## 脚本执行完成
[task] %s done
args %v
执行时间: %s
错误: %s`
